<?php


namespace App\Concern;


use App\Utils\CustomUtils;
use Hyperf\Database\ConnectionInterface;
use Hyperf\Database\Query\Builder;
use Hyperf\DbConnection\Db;
use Hyperf\Utils\Arr;

/**
 * 通用Dao函数封装, 包含单表增删改查和联表列表查询, 联表函数实现在子类种覆写
 * Class BaseDao
 *
 * @package App\Concern
 */
abstract class BaseDao {

    /**
     * 获取表名
     *
     * @return string
     */
    abstract public static function table (): string;

    /**
     * 单表增删改查
     */
//    use BaseDaoSingleTrait;

    /**
     * 通用列表查询
     */
//    use BaseDaoCommonTrait;

    /**
     * 主键字段名
     */
    protected $pk = "id";

    /**
     * 创建/更新时间, 如果设为null, 则不会自动更新指定字段
     */
    protected $createTime = "createTime";
    protected $updateTime = "updateTime";

    /**
     * 软删除标记字段, 如果设置为null, 则不支持软删除
     */
    protected $softDelete = "delFlag";

    abstract protected function _buildConnectionTable() : ConnectionInterface;

    /**
     * 分页逻辑
     * @param Builder $builder
     * @param         $page
     * @param         $limit
     * @return Builder
     */
    protected function _buildPageLimit (Builder $builder, $page, $limit) {

        if (!is_null($page) && !is_null($limit)) {
            $builder->offset(($page - 1) * $limit)->limit($limit);
        }

        return $builder;
    }

    /**
     * 排序逻辑
     * @param Builder $builder
     * @param array   $params
     * @return mixed
     */
    protected function _buildOrder (Builder $builder, $params = []) {

        $builder->orderBy("main." . $this->pk, 'asc');

        return $builder;
    }

    /**
     * 查询逻辑
     * @param $params
     * @return Builder
     */
    protected function _buildQueryString ($params) {

        $main = sprintf("%s AS main", $this->table());
        
        $builder = Db::table($main);

        // like
        // Arr::exists($params, "name") && $builder->where('main.name', 'like', '%' . $param['name'] . '%');

        // equal || in
        // Arr::exists($params, "status") && $builder->where('main.status',$param['status']);

        // between 闭区间
        // Arr::exists($params, "createTime") && $builder->whereBetween('main.createTime', $param['createTime']);

        return $builder;
    }

    /**
     * 补充创建时间
     * @param $data
     * @return mixed
     */
    protected function _fillCreateTime ($data) {

        if (!is_null($this->createTime) && !Arr::exists($data, $this->createTime)) {
            // 创建时间自动 && 未传入创建时间
            // $data[$this->createTime] = date("Y-m-d H:i:s");
            $data[$this->createTime] = time();
        }

        return $data;
    }

    /**
     * 补充更新时间
     * @param $data
     * @return mixed
     */
    protected function _fillUpdateTime ($data) {

        if (!is_null($this->updateTime) && !Arr::exists($data, $this->updateTime)) {
            // 更新时间自动 && 未传入更新时间
            $data[$this->updateTime] = date("Y-m-d H:i:s");
        }

        return $data;
    }

    /**
     * 主键获取
     * @param $id
     * @return Model|Builder|object|null
     */
    public function get ($id) {
        return $this->getWhere([$this->pk => $id]);
    }

    /**
     * 条件获取
     * @param $where
     * @return Model|Builder|object|null
     */
    public function getWhere ($where) {
        return $this->_buildConnectionTable()->table($this->table())->where($where)->orderByDesc("createTime")->first();
    }

    /**
     * 条件数量
     * @param $where
     * @return int
     */
    public function getWhereCount ($where) {
        return $this->_buildConnectionTable()->table($this->table())->where($where)->count();
    }

    /**
     * 条件列表
     * @param        $where
     * @param null   $orderBy
     * @param null[] $paginate
     * @return array
     */
    public function getWhereList ($where, $orderBy = null, $paginate = [null, null]) {

        $builder = $this->_buildConnectionTable()->table($this->table())->where($where);
        $builder = $this->_buildPageLimit($builder, $paginate[0], $paginate[1]);

        if (is_string($orderBy)) {
            $builder->orderBy($orderBy);
        }
        else if (is_array($orderBy)) {
            foreach ($orderBy as $k => $v) {
                $builder->orderBy($k, $v);
            }
        }

        return $builder->get()->toArray();
    }

    /**
     * 插入
     * @param $data
     * @return bool|int
     */
    public function add ($data) {

        if (!Arr::isAssoc($data)) {
            // 非关联数组, 批量插入
            foreach ($data as $k => $item) {
                $item = $this->_fillCreateTime($item);
                $item = $this->_fillUpdateTime($item);
                $data[$k] = $item;
            }

            return $this->_buildConnectionTable()->table($this->table())->insert($data);
        }
        else {
            // 关联数组, 单条插入

            $data = $this->_fillCreateTime($data);
            $data = $this->_fillUpdateTime($data);

            return $this->_buildConnectionTable()->table($this->table())->insertGetId($data);
        }
    }

    public function insert ($data) {
        return $this->add($data);
    }

    /**
     * 更新
     * @param $id
     * @param $data
     * @return int
     */
    public function set ($id, $data) {
        return $this->setWhere(['id' => $id], $data);
    }

    public function update ($id, $data) {
        return $this->set($id, $data);
    }

    /**
     * 条件更新
     * @param $where
     * @param $data
     * @return int
     */
    public function setWhere ($where, $data) {

        $data = $this->_fillUpdateTime($data);
        return $this->_buildConnectionTable()->table($this->table())->where($where)->update($data);
    }

    public function updateWhere ($where, $data) {
        return $this->setWhere($where, $data);
    }

    /**
     * 删除
     * @param      $id
     * @param bool $soft
     * @return int
     */
    public function del ($id, $soft = true) {
        return $this->delWhere(['id' => $id], $soft);
    }

    /**
     * 条件删除
     * @param      $where
     * @param bool $soft
     * @return int
     */
    public function delWhere ($where, $soft = true) {
        if ($soft && !is_null($this->softDelete)) {
            // 要求软删除, 并且支持软删除
            $this->updateWhere($where, [$this->softDelete => 1]);
        }
        else {
            return $this->_buildConnectionTable()->table($this->table())->where($where)->delete();
        }
    }

    /**
     * 通用条件列表
     * @param      $param
     * @param null $page
     * @param null $limit
     * @return mixed
     */
    public function getList ($param, $page = null, $limit = null) {
        $builder = $this->_buildQueryString($param);
        $builder = $this->_buildOrder($builder, $param);
        $builder = $this->_buildPageLimit($builder, $page, $limit);
        return $builder->get()->toArray();
    }

    /**
     * 通用条件数量
     * @param $param
     * @return int
     */
    public function getCount ($param) {
        $builder = $this->_buildQueryString($param);
        return $builder->count();
    }

}
